package com.example.mydemo.util;

import com.example.mydemo.entity.Clock;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.*;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ClockDataInserter {
    private static class EmployeeInfo {
        private final Long employeeId;
        private final LocalDate hireDate;

        public EmployeeInfo(Long employeeId, LocalDate hireDate) {
            this.employeeId = employeeId;
            this.hireDate = hireDate;
        }

        public Long getEmployeeId() { return employeeId; }
        public LocalDate getHireDate() { return hireDate; }
    }

    // ====================== 数据库配置 ======================
    private static final String DB_URL = "jdbc:mysql://localhost:3306/my_spring_boot_db?useSSL=false&serverTimezone=UTC";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "root";
    private static final String INSERT_SQL = "INSERT INTO c_clock (" +
            "employee_id, clock_type, clock_status, clock_time, location, remark, " +
            "isdelete, update_by, update_time, create_by, create_time) " +
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

    // ====================== 考勤规则配置 ======================

    private static final String COMPANY_LOCATION = "116.404,39.915";     // 公司位置（经纬度）
    private static final double LOCATION_OFFSET = 0.01;                  // 位置随机偏移量（±0.01度）
    private static int totalInserted = 0;

    // ====================== 随机数据配置 ======================
    private static final Random RANDOM = new Random();


    public static void main(String[] args) {

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
            conn.setAutoCommit(false);

            // 1. 查询有效员工信息（ID+雇佣日期）
            List<EmployeeInfo> employees = getEmployeeInfos(conn);
            if (employees.isEmpty()) {
                System.err.println("员工表无数据，无法生成打卡记录！");
                return;
            }

            // 2. 分批生成并插入打卡记录（关键优化：每1000条插入一次）
            int batchSize = 1000;       // 批次大小（可根据内存调整）
            List<Clock> batchBuffer = new ArrayList<>(batchSize); // 批次缓冲区

            for (EmployeeInfo emp : employees) {
                // 生成当前员工的所有打卡记录（按天生成）
                List<Clock> empClocks = generateEmployeeClocks(emp, conn);

                // 将当前员工的记录添加到批次缓冲区
                for (Clock clock : empClocks) {
                    batchBuffer.add(clock);

                    // 缓冲区满时插入数据库并清空
                    if (batchBuffer.size() >= batchSize) {
                        insertBatchAndClear(conn, batchBuffer);
                        totalInserted += batchSize; // 累加本次插入数量
                        System.out.println("成功插入 " + totalInserted + " 条打卡记录！");
                    }
                }
            }

            // 插入最后一批剩余记录（不足1000条）
            if (!batchBuffer.isEmpty()) {
                insertBatchAndClear(conn, batchBuffer);
            }

            System.out.println("成功插入 " + getTotalInserted() + " 条打卡记录！");

        } catch (SQLException e) {
            System.err.println("数据库操作失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 生成单个员工的所有打卡记录（从雇佣日期到今天）
     */
    private static List<Clock> generateEmployeeClocks(EmployeeInfo emp, Connection conn) throws SQLException {
        List<Clock> records = new ArrayList<>();
        DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        Random random = new Random(); // 员工级随机数生成器（确保同一员工打卡时间随机但稳定）

        LocalDate currentDate = LocalDate.now();
        LocalDate startDate = emp.getHireDate();

        // 校验雇佣日期有效性（不能晚于今天）
        if (startDate.isAfter(currentDate)) {
            System.out.printf("员工 %d 的雇佣日期 %s 晚于今天，跳过%n", emp.getEmployeeId(), startDate);
            return records;
        }

        // 遍历雇佣日期到今天的所有日期
        for (LocalDate date = startDate; !date.isAfter(currentDate); date = date.plusDays(1)) {
            // 跳过周末（周六=6，周日=7）
            if (date.getDayOfWeek().getValue() >= 6) continue;

            // 生成当日打卡次数（0/1/2次）
            int clockCount = generateDailyClockCount(random);

            switch (clockCount) {
                case 0:
                    // 不生成记录
                    break;
                case 1:
                    // 随机选择生成上班或下班打卡（各50%概率）
                    if (random.nextBoolean()) {
                        // 生成上班打卡（时间范围：8:30-9:30）
                        Clock workRecord = generateWorkRecord(emp.getEmployeeId(), date, dtFormatter,random);
                        records.add(workRecord);
                    } else {
                        // 生成下班打卡（时间范围：17:30-18:30）
                        Clock offRecord = generateOffRecord(emp.getEmployeeId(), date, dtFormatter, random);
                        records.add(offRecord);
                    }
                    break;
                case 2:
                    // 生成完整上下班打卡
                    Clock workRecord = generateWorkRecord(emp.getEmployeeId(), date, dtFormatter, random);
                    Clock offRecord = generateOffRecord(emp.getEmployeeId(), date, dtFormatter, random);
                    records.add(workRecord);
                    records.add(offRecord);
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + clockCount);
            }
        }
        return records;
    }

    /**
     * 生成单条上班打卡记录（带随机时间+状态判断）
     */
    // 原范围：8:30-9:30（60分钟）
// 修改后：正常时间8:30-9:00（30分钟，概率80%），迟到9:00-9:30（30分钟，概率15%），严重迟到>9:30（概率5%）
    private static Clock generateWorkRecord(Long employeeId, LocalDate date, DateTimeFormatter formatter,
                                            Random random) {
        // 正常时间范围（8:30-9:00）占80%，迟到（9:00-9:30）占15%，严重迟到（>9:30）占5%
        double timeProb = random.nextDouble();
        LocalTime clockTime;
        if (timeProb < 0.97) {
            // 正常时间：8:30-9:00（30分钟）
            clockTime = LocalTime.of(8, 30).plusMinutes(random.nextInt(31));
        } else if (timeProb < 0.99) {
            // 迟到：9:00-9:30（30分钟）
            clockTime = LocalTime.of(9, 0).plusMinutes(random.nextInt(31));
        } else {
            // 严重迟到：>9:30（随机）
            clockTime = LocalTime.of(9, 30).plusMinutes(random.nextInt(31));
        }

        // 判断状态（正常/迟到）
        int status;
        String remark;
        LocalTime workStart = LocalTime.of(9, 0); // 上班时间9:00
        Duration lateThreshold = Duration.ofMinutes(30); // 迟到30分钟阈值
        if (clockTime.isBefore(workStart.plus(lateThreshold))) {
            status = 1; // 正常（≤9:30）
            remark = "正常";
        } else {
            status = 2; // 迟到（>9:30）
            Duration delay = Duration.between(workStart, clockTime);
            int minutes = (int) delay.toMinutes();
            remark = String.format("迟到%d分钟", minutes);
        }

        // 生成位置（公司附近）
        String location = generateRandomLocation();

        return buildClockRecord(employeeId, 1, status, formatter.format(date.atTime(clockTime)), location, remark);
    }

    /**
     * 生成单条下班打卡记录（带随机时间+状态判断）
     */
    private static Clock generateOffRecord(Long employeeId, LocalDate date, DateTimeFormatter formatter,
                                           Random random) {
        // 正常时间范围（17:30-18:00）占85%，早退（17:00-17:30）占10%，严重早退（<17:00）占5%
        double timeProb = random.nextDouble();
        LocalTime clockTime;
        if (timeProb < 0.98) {
            // 正常时间：17:30-18:00（30分钟）
            clockTime = LocalTime.of(18, 0).plusMinutes(random.nextInt(31));
        } else if (timeProb < 0.99) {
            // 早退：17:00-17:30（30分钟）
            clockTime = LocalTime.of(17, 30).plusMinutes(random.nextInt(31));
        } else {
            // 严重早退：<17:00（随机）
            clockTime = LocalTime.of(17, 30).minusMinutes(random.nextInt(31));
        }

        // 判断状态（正常/早退）
        int status;
        String remark;
        LocalTime workEnd = LocalTime.of(18, 0); // 下班时间18:00
        if (clockTime.isAfter(workEnd)) {
            status = 1; // 正常（≥17:30）
            remark = "正常";
        } else {
            status = 3; // 早退（<17:30）
            Duration early = Duration.between(clockTime, workEnd);
            int minutes = (int) early.toMinutes();
            remark = String.format("早退%d分钟", minutes);
        }

        // 生成位置（公司附近）
        String location = generateRandomLocation();

        return buildClockRecord(employeeId, 2, status, formatter.format(date.atTime(clockTime)), location, remark);
    }

    /**
     * 生成公司位置附近的随机经纬度
     */
    private static String generateRandomLocation() {
        double[] companyCoords = parseLocation(COMPANY_LOCATION);
        double randomLon = companyCoords[0] + (RANDOM.nextDouble() - 0.5) * 2 * LOCATION_OFFSET;
        double randomLat = companyCoords[1] + (RANDOM.nextDouble() - 0.5) * 2 * LOCATION_OFFSET;
        return String.format("%.6f,%.6f", randomLon, randomLat);
    }

    /**
     * 解析位置字符串（经度,纬度）为数组
     */
    private static double[] parseLocation(String location) {
        String[] parts = location.split(",");
        return new double[]{Double.parseDouble(parts[0]), Double.parseDouble(parts[1])};
    }

    /**
     * 构造打卡记录对象（统一入口）
     */
    private static Clock buildClockRecord(Long empId, int type, int status,
                                          String time, String location, String remark) {
        return new Clock(
                null,       // id（自增）
                empId,
                type,
                status,
                time,
                location,
                remark
        );
    }

    /**
     * 批量插入打卡记录（并清空缓冲区）
     */
    private static int insertBatchAndClear(Connection conn, List<Clock> buffer) throws SQLException {
        int insertedCount = 0;
        try (PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL)) {
            int batchSize = 1000;
            for (int i = 0; i < buffer.size(); i++) {
                Clock record = buffer.get(i);
                pstmt.setLong(1, record.getEmployeeId());
                pstmt.setInt(2, Math.toIntExact(record.getClockType()));
                pstmt.setInt(3, Math.toIntExact(record.getClockStatus()));
                pstmt.setString(4, String.valueOf(record.getClockTime())); // 已格式化的字符串
                pstmt.setString(5, record.getLocation());
                pstmt.setString(6, record.getRemark());
                pstmt.setInt(7, Math.toIntExact(record.getIsDelete())); // 默认0（未删除）
                pstmt.setString(8, "system"); // 示例：更新人（可根据需求调整）
                pstmt.setTimestamp(9, Timestamp.valueOf(LocalDateTime.now())); // 当前时间
                pstmt.setString(10, "system"); // 示例：创建人（可根据需求调整）
                pstmt.setTimestamp(11, Timestamp.valueOf(LocalDateTime.now())); // 当前时间
                pstmt.addBatch();

                // 每1000条执行一次批量插入
                if (i % batchSize == 0) {
                    pstmt.executeBatch();
                    conn.commit();
                }
            }
            // 执行剩余记录
            pstmt.executeBatch();
            conn.commit();
            insertedCount = buffer.size();
        }
        buffer.clear(); // 清空缓冲区释放内存
        return insertedCount;
    }

    /**
     * 生成当日打卡次数（0/1/2次）
     */
    private static int generateDailyClockCount(Random random) {
        double probability = random.nextDouble();
        if (probability < 0.01) {
            return 0; // 20%概率不打卡
        } else if (probability < 0.02) { // 0.2-0.5为30%概率
            return 1; // 30%概率打1次
        } else {
            return 2; // 50%概率打2次
        }
    }

    /**
     * 查询员工表中所有有效员工（ID+雇佣日期）
     */
    private static List<EmployeeInfo> getEmployeeInfos(Connection conn) throws SQLException {
        List<EmployeeInfo> employeeInfos = new ArrayList<>();
        String sql = "SELECT employee_id, hire_date FROM c_employee WHERE is_delete = 0";
        try (Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            while (rs.next()) {
                Long empId = rs.getLong("employee_id");
                LocalDate hireDate = rs.getObject("hire_date", LocalDate.class);
                employeeInfos.add(new EmployeeInfo(empId, hireDate));
            }
        }
        return employeeInfos;
    }

    // 统计总插入数量（示例，可根据需要调整）
    private static int getTotalInserted() {
        // 实际生产环境中建议通过数据库查询或日志统计
        return totalInserted; // 此处为示例，需根据实际情况实现
    }
}